package atmosphere;

import com.jme3.app.Application;
import com.jme3.app.state.AppState;
import com.jme3.app.state.AppStateManager;
import com.jme3.font.BitmapFont;
import com.jme3.font.BitmapText;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import java.text.DecimalFormat;
import java.text.NumberFormat;

/**
 * @author jiyarza
 */
public class PlanetUIState implements AppState, ActionListener {

    private static final String UI_XYZ = "XYZ";
    private static final String UI_HEIGHT = "Height";
    private static final String UI_SAMPLES = "Samples";
    private static final String UI_KR = "Kr";
    private static final String UI_KM = "Km";
    private static final String UI_ESUN = "ESun";
    private static final String UI_G = "G";
    private static final String UI_RED = "Red";
    private static final String UI_GREEN = "Green";
    private static final String UI_BLUE = "Blue";
    private static final String UI_EXPOSURE = "Exposure";

    private static final String UI_SHIFT = "[SHIFT] decreases value";
    private static final String UI_CTRL = "[CTRL] stepx10";
    private static final String UI_NEAR = "[HOME] Close view";
    private static final String UI_FAR = "[END] Far view";
    private static final String FONT = "Interface/Fonts/Console.fnt";

    private BitmapFont font;
    private BitmapText xyz;
    private BitmapText height;
    private BitmapText samples;
    private BitmapText Kr;
    private BitmapText Km;
    private BitmapText ESun;
    private BitmapText G;
    private BitmapText wRed;
    private BitmapText wGreen;
    private BitmapText wBlue;
    private BitmapText exposure;
    private BitmapText shift;
    private BitmapText ctrl;
    private BitmapText near;
    private BitmapText far;

    private Prototype prototype;
    private Planet planet;

    private NumberFormat format4;
    private NumberFormat format2;


    private float sign = 1.0f;
    private float multiplier = 1.0f;
    
    public PlanetUIState(Planet planet) {
        format4 = new DecimalFormat();
        format4.setMaximumFractionDigits(4);
        format2 = new DecimalFormat();
        format2.setMaximumFractionDigits(2);
        this.planet = planet;
        this.prototype = Prototype.getInstance();        
    }

    public void setupHUD() {       
        font = prototype.getAssetManager().loadFont(FONT);

        xyz = new BitmapText(font, false);
        height = new BitmapText(font, false);
        ESun = new BitmapText(font, false);
        G = new BitmapText(font, false);
        Km = new BitmapText(font, false);
        Kr = new BitmapText(font, false);
        samples = new BitmapText(font, false);
        wBlue = new BitmapText(font, false);
        wGreen = new BitmapText(font, false);
        wRed = new BitmapText(font, false);
        exposure = new BitmapText(font, false);
        shift = new BitmapText(font, false);
        ctrl = new BitmapText(font, false);
        near = new BitmapText(font, false);
        far = new BitmapText(font, false);


        xyz.setColor(ColorRGBA.Gray);
        height.setColor(ColorRGBA.Gray);
        shift.setColor(ColorRGBA.Gray);
        ctrl.setColor(ColorRGBA.Gray);
        near.setColor(ColorRGBA.Gray);
        far.setColor(ColorRGBA.Gray);

        int maxrows = prototype.getCamera().getHeight() / Math.round(xyz.getLineHeight());

        loadText(xyz, UI_XYZ, font, 0, maxrows--, 0);
        loadText(height, UI_HEIGHT, font, 0, maxrows--, 0);
        loadText(ESun, UI_ESUN, font, 0, maxrows--, 0);
        loadText(G, UI_G, font, 0, maxrows--, 0);
        loadText(Kr, UI_KR, font, 0, maxrows--, 0);
        loadText(Km, UI_KM, font, 0, maxrows--, 0);
        loadText(wRed, UI_RED, font, 0, maxrows--, 0);
        loadText(wGreen, UI_GREEN, font, 0, maxrows--, 0);
        loadText(wBlue, UI_BLUE, font, 0, maxrows--, 0);
        loadText(samples, UI_SAMPLES, font, 0, maxrows--, 0);
        loadText(exposure, UI_EXPOSURE, font, 0, maxrows--, 0);
        loadText(shift, UI_SHIFT, font, 0, maxrows--, 0);
        loadText(ctrl, UI_CTRL, font, 0, maxrows--, 0);
        loadText(near, UI_NEAR, font, 0, maxrows--, 0);
        loadText(far, UI_FAR, font, 0, maxrows--, 0);
    }

    /**
     * This utility method has been borrowed from the Jme3 examples
     */
    private void loadText(BitmapText txt, String text, BitmapFont font, float x, float y, float z) {
        txt.setSize(font.getCharSet().getRenderedSize());
        txt.setLocalTranslation(txt.getLineWidth() * x, txt.getLineHeight() * y, z);
        txt.setText((CharSequence) text);
        prototype.getGuiNode().attachChild(txt);
    }   

    public void update(float tpf) {
        Vector3f loc = prototype.getCamera().getLocation();
        String x = format2.format(loc.x);
        String y = format2.format(loc.y);
        String z = format2.format(loc.z);
        String s = new StringBuilder(": (").append(x)
                       .append(" : ").append(y)
                       .append(" : ").append(z)
                       .append(")").toString();

        this.xyz.setText(new StringBuilder(UI_XYZ).append(s));
        this.height.setText(new StringBuilder(UI_HEIGHT).append(": ")
                                .append(format2.format(prototype.getCamera()
                                .getLocation().length() - Prototype.PLANET_RADIUS)));
        this.ESun.setText(new StringBuilder(UI_ESUN).append("[E]: ")
                .append(format4.format(planet.getESun())));
        this.G.setText(new StringBuilder(UI_G).append("[H]: ")
                .append(format4.format(planet.getG())));
        this.Km.setText(new StringBuilder(UI_KM).append("[M]: ")
                .append(format4.format(planet.getKm())));
        this.Kr.setText(new StringBuilder(UI_KR).append("[Y]: ")
                .append(format4.format(planet.getKr())));
        this.samples.setText(new StringBuilder(UI_SAMPLES).append("[P]: ")
                .append(planet.getnSamples()));
        this.wRed.setText(new StringBuilder(UI_RED).append("[R]: ")
                .append(format4.format(planet.getWavelength().x)));
        this.wGreen.setText(new StringBuilder(UI_GREEN).append("[G]: ")
                .append(format4.format(planet.getWavelength().y)));
        this.wBlue.setText(new StringBuilder(UI_BLUE).append("[B]: ")
                .append(format4.format(planet.getWavelength().z)));
        this.exposure.setText(new StringBuilder(UI_EXPOSURE).append("[X]: ")
                .append(format2.format(planet.getExposure())));
    }

    private void setupKeys() {
        prototype.getInputManager().addMapping(UI_ESUN, new KeyTrigger(KeyInput.KEY_E));
        prototype.getInputManager().addMapping(UI_G, new KeyTrigger(KeyInput.KEY_H));
        prototype.getInputManager().addMapping(UI_KM, new KeyTrigger(KeyInput.KEY_M));
        prototype.getInputManager().addMapping(UI_KR, new KeyTrigger(KeyInput.KEY_Y));
        prototype.getInputManager().addMapping(UI_SAMPLES, new KeyTrigger(KeyInput.KEY_P));
        prototype.getInputManager().addMapping(UI_RED, new KeyTrigger(KeyInput.KEY_R));
        prototype.getInputManager().addMapping(UI_GREEN, new KeyTrigger(KeyInput.KEY_G));
        prototype.getInputManager().addMapping(UI_BLUE, new KeyTrigger(KeyInput.KEY_B));
        prototype.getInputManager().addMapping(UI_EXPOSURE, new KeyTrigger(KeyInput.KEY_X));
        prototype.getInputManager().addMapping(UI_SHIFT, new KeyTrigger(KeyInput.KEY_LSHIFT), new KeyTrigger(KeyInput.KEY_RSHIFT));
        prototype.getInputManager().addMapping(UI_CTRL, new KeyTrigger(KeyInput.KEY_LCONTROL), new KeyTrigger(KeyInput.KEY_RCONTROL));
        prototype.getInputManager().addMapping(UI_NEAR, new KeyTrigger(KeyInput.KEY_HOME));
        prototype.getInputManager().addMapping(UI_FAR, new KeyTrigger(KeyInput.KEY_END));

        prototype.getInputManager().addListener(this,
                                            UI_ESUN,
                                            UI_G,
                                            UI_KM,
                                            UI_KR,
                                            UI_SAMPLES,
                                            UI_RED,
                                            UI_GREEN,
                                            UI_BLUE,
                                            UI_EXPOSURE,
                                            UI_SHIFT,
                                            UI_CTRL,
                                            UI_NEAR,
                                            UI_FAR
                                            );
    }

    public void onAction(String name, boolean value, float tpf) {
      if (name.equals(UI_SHIFT)) {
          if (value) {
              sign=-1;
          } else {
              sign=1;
          }
      }
      if (name.equals(UI_CTRL)) {
          if (value) {
              multiplier = 10.0f;
          } else {
              multiplier = 1.0f;
          }
      }
      if (name.equals(UI_ESUN) && value) {
        planet.setESun(planet.getESun() + (sign*0.1f*multiplier));
      } else if (name.equals(UI_G) && value) {
        planet.setG(planet.getG() + (sign*0.0001f*multiplier));
      } else if (name.equals(UI_KM) && value) {
        planet.setKm(planet.getKm() + (sign*0.00001f*multiplier));
      } else if (name.equals(UI_KR) && value) {
        planet.setKr(planet.getKr() + (sign*0.00001f*multiplier));
      } else if (name.equals(UI_RED) && value) {
        planet.setRed(planet.getWavelength().x + (sign*0.001f*multiplier));
      } else if (name.equals(UI_GREEN) && value) {
        planet.setGreen(planet.getWavelength().y + (sign*0.001f*multiplier));
      } else if (name.equals(UI_BLUE) && value) {
        planet.setBlue(planet.getWavelength().z + (sign*0.001f*multiplier));
      } else if (name.equals(UI_SAMPLES) && value) {
        planet.setSamples(planet.getnSamples() + ((int)sign*1*((int)multiplier)));
      } else if (name.equals(UI_EXPOSURE) && value) {
        planet.setExposure(planet.getExposure() + (sign*0.01f*multiplier));
      } else if (name.equals(UI_NEAR) && value) {
        prototype.closeView();
      } else if (name.equals(UI_FAR) && value) {
        prototype.farView();
      }
      planet.updateCalculations();
    }

    public void initialize(AppStateManager stateManager, Application app) {        
        setupKeys();
        setupHUD();
        if (planet == null) throw new IllegalStateException("Planet cannot be NULL.");
    }

    public boolean isInitialized() {
        return font != null;
    }

    public void setActive(boolean active) {        
    }

    public boolean isActive() {
        return true;
    }

    public void stateAttached(AppStateManager stateManager) {
    }

    public void stateDetached(AppStateManager stateManager) {
    }

    public void render(RenderManager rm) {
    }

    public void postRender() {
    }

    public void cleanup() {
    }

    public void setEnabled(boolean active) {        
    }

    public boolean isEnabled() {
        return true;
    }
}
